module renderers.Model;
import frontend.Types;
import frontend.Model;
import framework.Renderer;
import derelict.sdl.sdl;
import derelict.opengl.gl;
import derelict.opengl.glu;
import maths.Vec;
import utils.Memory;

enum ModelRendererFunc{
	RenderNothing=0,
	RenderNotSkinned,
	RenderBones,
	RenderSkinned
}

class ModelRenderer {
	vec3[] verticesToDraw;
	vec3[] normalsToDraw;
	this(Model model){
		renderer.register(&this.update);
		this.model=model;
		verticesToDraw.alloc(model.positions.length);
		normalsToDraw.alloc(model.positions.length);
	}
	
	private Model model;
	private ModelRendererFunc func=ModelRendererFunc.RenderNotSkinned;
	
	private void update(){
		
		model.update;
		switch(func){
			case ModelRendererFunc.RenderNotSkinned: unskinnedRender(); break;
			case ModelRendererFunc.RenderNothing: blankRender(); break;
			case ModelRendererFunc.RenderBones: renderBones(); break;
			case ModelRendererFunc.RenderSkinned: renderSkinned(); break;
		}
	}
	
	void set(ModelRendererFunc nf){
		func=nf;
	}
	
	private void blankRender(){
		
	}

	private void unskinnedRender(){
		
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		glEnable(GL_CULL_FACE);
		glEnable(GL_DEPTH_TEST);
		
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glBegin(GL_TRIANGLES);
		foreach (i; model.indices) {
			glColor3f(1, 1, 1);
			glNormal3fv(&model.normals[i].x);
			glVertex3fv(&model.positions[i].x);
			//writefln(model.normals[i]);
		}
		glEnd();
	}
	
	private void renderBones(){
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);
		glDisable(GL_LIGHT0);
		glDisable(GL_CULL_FACE);
		glDisable(GL_DEPTH_TEST);
		
		Skeleton skeleton=model.skeleton;
		glDisable(GL_TEXTURE_2D);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glBegin(GL_LINES);
			glColor3f(1, 0, 0);
			renderBone(skeleton.pelvis);
		glEnd();
	}
	

	
	private void renderBone(Bone* bone){
		foreach(child;bone.children){
			glVertex3fv(&(vec3.convert(bone.coordSys.origin).x));
			glVertex3fv(&(vec3.convert(child.coordSys.origin).x));
		}
		foreach(child;bone.children){
			renderBone(child);
		}
	}
	
	private void renderSkinned(){
		foreach(index,p;model.positions){
			verticesToDraw[index]=vec3.zero;
			normalsToDraw[index]=vec3.zero;
			foreach(i,bone;model.bones[index]){
				verticesToDraw[index]+=model.weights[index][i]* model.skeleton.rotandtrans[bone].xform(model.offsets[index][i]);
				normalsToDraw[index]+=model.weights[index][i]* model.skeleton.rotonly[bone].xform(model.normals[index]);
			}
			normalsToDraw[index].normalize;
		}
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		glEnable(GL_CULL_FACE);
		glEnable(GL_DEPTH_TEST);
		
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glBegin(GL_TRIANGLES);
		foreach (i; model.indices) {
			glColor3f(1, 1, 1);
			glNormal3fv(&normalsToDraw[i].x);
			glVertex3fv(&verticesToDraw[i].x);
			//writefln(model.normals[i]);
		}
		glEnd();
	}
}

import std.stdio;
import std.random;